module debugPanel {

	/**
	 * 方便查找ui类名的插件类;
	 * 对于列出的ui显示对象会临时动态添加一个属性 __debugName__;
	 * 使用方法:
	 * 首先通过程序的入口类中的addToStage事件的监听函数注册插件:DebugPanel.inst.init(this.stage);
	 * 注册后，pc端可以按下 esc 调出界面，这个时候随便点击舞台上能响应鼠标事件的可视对象,
	 * 插件就会显示一个列出列出该对象父级的所有子级显示对象,
	 * 如果该对象是容器还会列出其所有子级;(均需要满足对象的显示区域包含鼠标点才会显示出来).
	 * 点击列表中的按钮,如果该对象是容器会再次列出其所有子级;
	 * 点击列表上的 '快照' 按钮
	 * 会显示该对象的在舞台的坐标、尺寸信息以及类名;
	 * 最多显示20个显示对象的信息;可以通过 DebugPanel.MAX_NUM 设置;	 
	*/
	export class DebugPanel {
		public static PRO_NAME: string = "__debugName__";
		public static MAX_NUM: number = 20; //列表最大数量
		private static _inst: DebugPanel;

		public constructor() {

		}

		public static get inst(): DebugPanel {
			if (!DebugPanel._inst) {
				DebugPanel._inst = new DebugPanel();
			}
			return DebugPanel._inst;
		}

		private _stage: egret.Stage;
		private _view: UIView;
		private _boundRect: egret.Rectangle;
		public isViewShow: boolean = false;
		public init(stage: egret.Stage): void {
			this._stage = stage;
			this._view = new UIView();
			this._boundRect = new egret.Rectangle();
			this._stage.addEventListener(egret.TouchEvent.TOUCH_TAP, this.onStageClick, this);
			document.addEventListener("keydown", this.keyDownFn); //添加键盘事件

		}

		private keyDownFn(evt: KeyboardEvent): void {
			//该函数内的this对象是document
			if (evt.keyCode == 27) {
				DebugPanel.inst.isViewShow = !DebugPanel.inst.isViewShow;
				DebugPanel.inst.show(DebugPanel.inst.isViewShow);
			}
		}

		private onStageClick(e: egret.TouchEvent): void {
			let tar: egret.DisplayObject = e.target;
			if (tar && this.isViewShow && !(tar instanceof UIView) &&
				!(tar instanceof ContentButton)) {
				this.showList(tar, e.stageX, e.stageY, false);
			}
		}

		public showList(tar: egret.DisplayObject, stageX: number, stageY: number, ignorePoint: boolean): void {
			this._view.update(this.findTarList(tar, stageX, stageY, ignorePoint));
		}
		public show(show: boolean): void {
			if (show) {
				this._stage.addChild(this._view);
			} else {
				this._stage.removeChild(this._view);
			}
		}

		/**
		 * 找出目标显示对象的父级和父级的其他子级
		*/
		public findTarList(tar: egret.DisplayObject, stageX: number, stageY: number, ignorePoint: boolean): Array<egret.DisplayObject> {
			var ret: Array<egret.DisplayObject> = new Array<egret.DisplayObject>();
			var par: egret.DisplayObjectContainer = tar.parent;
			if (par) {
				this.getParChildren(par, ret, stageX, stageY, ignorePoint);
				if (ret.indexOf(par) == -1 && ret.length < DebugPanel.MAX_NUM) {
					ret.push(par); //最后一个是父级
				}
				if (tar instanceof egret.DisplayObjectContainer) {
					//如果目标是一个容器，也把它的子级显示出来
					this.getParChildren(tar, ret, stageX, stageY, ignorePoint);
				}
			} else {
				if (ret.indexOf(tar) == -1 && ret.length < DebugPanel.MAX_NUM) {
					ret.push(tar);
				}
			}

			return ret;
		}

		/**
		 * 筛选一个容器里面符合条件的子级 显示出来
		*/
		private getParChildren(par: egret.DisplayObjectContainer,
			ret: Array<egret.DisplayObject>,
			stageX: number, stageY: number,
			ignorePoint: boolean): void {

			//把鼠标点击的那刻的全局坐标转换成父级的本地坐标
			var parPoint: egret.Point = par.globalToLocal(stageX, stageY);
			var localX: number = parPoint.x;
			var localY: number = parPoint.y;

			var child: egret.DisplayObject;
			var numChild: number = par.numChildren - 1;
			var isUnderPoint: boolean;
			while (numChild >= 0) {
				child = par.getChildAt(numChild);

				numChild--;
				this._boundRect.x = child.x;
				this._boundRect.y = child.y;
				this._boundRect.width = child.width;
				this._boundRect.height = child.height;
				isUnderPoint = this._boundRect.contains(localX, localY); //判断当前鼠标是否触碰到该子级
				if (child instanceof UIView || child instanceof TargetItem ||
					child instanceof Snapshoot ||
					(!isUnderPoint && !ignorePoint)) {
					continue;
				}
				if (ret.indexOf(child) == -1) {
					ret.push(child);
					if (!child.name) {
						this.searchFieldName(par, child);
					}
					if (ret.length >= DebugPanel.MAX_NUM) {
						break;
					}
				}
			}

		}
		//递归搜索字段名 对于比较深层次的会很耗时
		private searchFieldName(par: egret.DisplayObjectContainer, child: egret.DisplayObject): void {
			var pros: string[] = Object.keys(par);
			//Object.getOwnPropertyNames()

			//找出在父级中定义的属性名
			var tarName: string;
			var f: boolean = par instanceof egret.Stage;
			for (var i in pros) {
				tarName = pros[i];
				if (par[tarName] == child) {
					f = true;
					child[DebugPanel.PRO_NAME] = tarName;
					break;
				}
			}
			if (!f) {
				par = par.parent;
				if (par) {
					this.searchFieldName(par, child);
				}

			}
		}

	} //end of uiview 

	/**
	 * 显示查找到的内容ui
	*/
	export class UIView extends egret.Sprite {

		private _items: Array<TargetItem>;
		private _itemFactory: Array<TargetItem>;
		private _btn: ContentButton;
		private _stpos: number = 0;
		private _snapshoot: Snapshoot;
		private _curOverTar: TargetItem;
		private _container: egret.Sprite;
		public constructor() {
			super();
			this._items = new Array<TargetItem>();
			this._itemFactory = new Array<TargetItem>();
			this._btn = new ContentButton();
			this.addChild(this._btn);
			this._btn.label = "收起";
			this._btn.touchEnabled = true;
			this._stpos = this._btn.y + this._btn.height;
			this.touchEnabled = true;
			//this.touchChildren = false;
			this._snapshoot = new Snapshoot();
			this._container = new egret.Sprite();
			this.addChild(this._container);
			this.addEventListener(egret.Event.ADDED_TO_STAGE, this.onAdded, this);
		}

		private onAdded(e: egret.Event): void {
			this.addEventListener(egret.TouchEvent.TOUCH_TAP, this.onClick, this);
			this.addEventListener(egret.Event.REMOVED_FROM_STAGE, this.onRemoved, this);
		}

		private onRemoved(e: egret.Event): void {
			this.removeEventListener(egret.Event.ADDED_TO_STAGE, this.onAdded, this);
			this.removeEventListener(egret.TouchEvent.TOUCH_TAP, this.onClick, this);
			this.addEventListener(egret.Event.ADDED_TO_STAGE, this.onAdded, this);
			this._snapshoot.clear();
			this.recycle();
		}

		private recycle(): void {
			var item: TargetItem;
			for (var i: number = 0; i < this._items.length; i++) {
				item = this._items.splice(i, 1)[0];
				i--;
				if (item.parent) {
					item.parent.removeChild(item);
				}
				this._itemFactory.push(item);
			}
			for (i = 0; i < this._itemFactory.length; i++) {
				item = this._itemFactory[i];
				item.ref = null;
				item[DebugPanel.PRO_NAME] = null;
			}
		}

		private onClick(e: egret.TouchEvent): void {
			var tar: egret.DisplayObject = e.target;
			if (tar == this._btn) {
				//DebugPanel.inst.isViewShow = !DebugPanel.inst.isViewShow;
				//DebugPanel.inst.show(DebugPanel.inst.isViewShow);
				this._container.visible = !this._container.visible;
				if (this._container.visible) {
					this._btn.label = "收起";
				} else {
					this._btn.label = "展开";
				}
			} else if (tar instanceof ViewIco) {
				var par: TargetItem = tar.parent as TargetItem;
				this.stage.addChild(this._snapshoot);
				this._snapshoot.update(par.ref, this.stage);
				e.stopPropagation();
			} else if (tar instanceof TargetItem) {
				//找出该类的父级 然后找出父级的所有子级列出来
				if (tar.ref.parent) {
					var p: egret.Point = tar.ref.parent.localToGlobal(tar.ref.x, tar.ref.y);
					DebugPanel.inst.showList(tar.ref, p.x, p.y, true);
				}
			}

		}

		public update(arr: Array<egret.DisplayObject>): void {
			this._snapshoot.clear();
			var len: number = arr.length;
			var itm: TargetItem;
			var pox: number = 0;
			var tar: egret.DisplayObject;
			var idx: number = -1;
			var items: Array<TargetItem> = new Array<TargetItem>();
			for (var i: number = 0; i < len; i++) {
				tar = arr[i];
				if (!(tar instanceof egret.DisplayObject)) {
					continue;
				}
				idx++;
				itm = this._items[idx];
				if (!itm) {
					if (this._itemFactory.length > 0) {
						itm = this._itemFactory.pop();
					} else {
						itm = new TargetItem();
					}
					this._items.push(itm);
				}
				itm.ref = tar;
				//this.addChild(itm);
				this._container.addChild(itm);
				itm.update(tar, this.stage);
				itm.x = 0;
				itm.y = this._stpos + pox;
				pox += 45;

			}
			idx++;
			for (; idx < this._items.length; idx++) {
				var rms: TargetItem[] = this._items.splice(i, 1);
				idx--;
				var rmOne: TargetItem = rms[0];
				if (this._itemFactory.indexOf(rmOne) == -1) {
					this._itemFactory.push(rmOne);
				}
				if (rmOne.parent) {
					rmOne.parent.removeChild(rmOne);
					if (rmOne.ref) {
						rmOne.ref[DebugPanel.PRO_NAME] = null;
						rmOne.ref = null;
					}
				}
			}

		}

	}

	/**
	 * 所有单个内容的基类
	*/
	export class ContentButton extends egret.Sprite {
		protected _gap: number = 4;
		public _txt: egret.TextField;
		public constructor() //构造函数不能有返回值
		{
			super();
			this.touchEnabled = this.touchChildren = false;
			this._txt = new egret.TextField();
			this._txt.textColor = 0xff0000;
			//this._txt.background = true;
			//this._txt.backgroundColor = 0xcccccc;
			this._txt.x = this._txt.y = this._gap;
			this.addChild(this._txt);

		}

		public set label(value: string) {
			this._txt.text = value;
			this.renderRect();
		}

		public update(tar: egret.DisplayObject, stage: egret.Stage): void {

		}
		public renderRect(clr: number = 0xcccccc): void {
			var g: egret.Graphics = this.graphics;
			g.clear();
			g.beginFill(clr);
			g.drawRect(0, 0, this._txt.textWidth + this._gap * 2, this._txt.textHeight + this._gap * 2);
			g.endFill();
		}
	}
	/**
	 * 定位快照的按钮
	*/
	export class ViewIco extends egret.Sprite {
		private _txt: egret.TextField;
		public constructor() {
			super();
			this.touchEnabled = true;
			this._txt = new egret.TextField();
			this._txt.textColor = 0xff0000;
			this.addChild(this._txt);
			this._txt.text = "快照";
			var gap: number = 2;
			this._txt.x = gap;
			this._txt.y = gap;

			this.graphics.beginFill(0x00ff00);
			this.graphics.drawRect(0, 0, this._txt.textWidth + gap * 2, this._txt.textHeight + gap * 2)
			this.graphics.endFill();

		}
	}
	/**
	 * 显示当前查找到的对象
	*/
	export class TargetItem extends ContentButton {
		public _ico: ViewIco;
		public constructor() {
			super();
			//this._gap = 8;
			this.touchEnabled = true;
			this.touchChildren = true;

			this._ico = new ViewIco();
			this.addChild(this._ico);

			this._txt.textColor = 0xffffff;
		}
		public ref: egret.DisplayObject;
		public update(tar: egret.DisplayObject, stage: egret.Stage): void {
			var cls: string = egret.getQualifiedClassName(tar);
			var tarName: string = tar[DebugPanel.PRO_NAME];
			var supCls: string = egret.getQualifiedSuperclassName(tar);
			if (!tarName) {
				tarName = "_field_"; //表示是一个无法知道的字段名
			}
			this._txt.text = `${tarName}:${cls}`;
			this.renderRect(0x666666);
			this._ico.y = (this.height - this._ico.height) / 2;
			this._ico.x = this._txt.x + this._txt.textWidth + 2;
		}
	}

	/**
	 * 快照轮廓类
	*/
	export class Snapshoot extends ContentButton {
		private _tarP: egret.Point;
		public constructor() //构造函数不能有返回值
		{
			super();
			this.touchEnabled = this.touchChildren = false;
			this._tarP = new egret.Point();
			this._txt.textColor = 0x990000;
			this._txt.background = true;
			this._txt.backgroundColor = 0x999999;
		}
		public update(tar: egret.DisplayObject, stage: egret.Stage): void {
			if (tar && tar.parent) {
				tar.parent.localToGlobal(tar.x, tar.y, this._tarP);
				var g: egret.Graphics = this.graphics;
				g.clear();
				g.lineStyle(3, 0xff0000);
				g.drawRect(this._tarP.x, this._tarP.y, tar.width, tar.height);
				var clsName: string = egret.getQualifiedClassName(tar);

				this._txt.text = `x=${tar.x},y=${tar.y},w=${tar.width},h=${tar.height},\ncls=${clsName}`;
				this._txt.x = this._tarP.x;
				var ty: number = Math.max(0, (this._tarP.y - this._txt.textHeight));
				ty = Math.min((stage.stageHeight - this._txt.textHeight), ty);
				this._txt.y = ty;

			}
		}

		public clear(): void {
			var g: egret.Graphics = this.graphics;
			g.clear();
			this._txt.text = "";
			if (this.parent) {
				this.parent.removeChild(this);
			}
		}


	}

}